package com.camtc.camcenter.config;

import com.camtc.camcenter.config.provider.JwtAuthenticationProvider;
import com.camtc.camcenter.custom.CamHttpResult;
import com.camtc.camcenter.filter.JwtAuthenticationFilter;
import com.camtc.camcenter.filter.JwtLoginFilter;
import com.camtc.camcenter.security.PersistentRememberMeImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;

import java.io.PrintWriter;

import static com.camtc.camcenter.custom.ResultStatusCode.NO_LOGIN;

/**
 * spring security web请求配置
 *
 * @author 先生
 * @date
 */

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 用户服务
     */
    private UserDetailsService userDetailsService;

    @Autowired
    public void setUserDetailsService(@Qualifier("cloudUserDetailsServiceImpl") UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    /**
     * 保持登录服务
     */
    private PersistentRememberMeImpl persistentRememberMe;

    @Autowired
    public void setPersistentRememberMe(PersistentRememberMeImpl persistentRememberMe) {
        this.persistentRememberMe = persistentRememberMe;
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        // 使用自定义的登陆身份验证组件
        auth.authenticationProvider(new JwtAuthenticationProvider(userDetailsService));
    }

    /**
     * http 请求过滤的资源
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 禁用csrf，由于使用的JWT，所以不需要csrf
        http.cors().and().csrf().disable()
                .authorizeRequests()
                // 跨域预检请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                // 所有用户可以访问的后台资源后缀
                .antMatchers("/css/**", "/js/**", "/images/**", "/webjars/**", "**/favicon.ico", "/**.html").permitAll()
                // 登录校验等URL
                .antMatchers("/jwt/**").permitAll()
                // swagger
                .antMatchers("/swagger*/**").permitAll()
                .antMatchers(
                        //swagger api json
                        "/v2/api-docs",
                        //用来获取支持的动作
                        "/swagger-resources/configuration/ui",
                        //用来获取api-docs的URL
                        "/swagger-resources",
                        //安全校验框架选择
                        "/swagger-resources/configuration/security",
                        "/swagger-ui.html").permitAll()
                .antMatchers("/vc.jpg").permitAll()
                // 其他请求需要身份认证
                .anyRequest().authenticated();
        // HTTP请求异常处理
        http.exceptionHandling().authenticationEntryPoint((req, resp, authException) -> {
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.print(CamHttpResult.failure(NO_LOGIN));
            out.flush();
            out.close();
        });
        // 开启记住登录,记住7天
        http.rememberMe().key("camtc-key").tokenRepository(persistentRememberMe);
        // 开启登录认证流程过滤器
        http.addFilterBefore(new JwtLoginFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
        // 退出登录处理器
        http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());
        // 访问控制时登录状态检测过滤器
        http.addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
    }


    /**
     * 获取验证管理的对象
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
}
